/**
 * 
 */
package edu.sjtu.se.prophet.driver;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;

import b4j.core.DefaultSearchData;
import b4j.core.Issue;
import b4j.core.LongDescription;
import b4j.core.session.HttpBugzillaSession;

/**
 * @author willard
 */
public class LinkPreparer extends DefaultPropertiesLoader {
    public static String B4J_CONFIG_FILE = "b4j.config";
    public static String SEARCH_DATA_KEYS = "b4j.data.keys";
    public static String SEARCH_DATA_VALUES = "b4j.data.values";
    public static String BUG_DATA_FILE = "b4j.out.data";
    public static String BUG_COMMENT_FILE = "b4j.out.comment";
    public static String BUG_NUMBER_LIMIT = "b4j.bugNumberLimit";

    public void prepare() throws ConfigurationException {

        if (!properties.containsKey(B4J_CONFIG_FILE)
                || !properties.containsKey(SEARCH_DATA_KEYS)
                || !properties.containsKey(SEARCH_DATA_VALUES)
                || !properties.containsKey(BUG_DATA_FILE)
                || !properties.containsKey(BUG_COMMENT_FILE))
            return;// TODO throw exception

        // Configure from file
        XMLConfiguration myConfig = new XMLConfiguration(new File(
                properties.getProperty(B4J_CONFIG_FILE)));

        // Create the session
        HttpBugzillaSession session = new HttpBugzillaSession();
        session.configure(myConfig);

        // Open the session
        if (session.open()) {

            String[] keys = properties.getProperty(SEARCH_DATA_KEYS).split(
                    SPLITER);
            String[] values = properties.getProperty(SEARCH_DATA_VALUES).split(
                    SPLITER);

            try {
                FileWriter dataWriter = new FileWriter(new File(
                        properties.getProperty(BUG_DATA_FILE)));
                FileWriter commentWriter = new FileWriter(new File(
                        properties.getProperty(BUG_COMMENT_FILE)));

                long limit = Long.MAX_VALUE;
                if (properties.containsKey(BUG_NUMBER_LIMIT)) {
                    try {
                        limit = Long.parseLong(properties
                                .getProperty(BUG_NUMBER_LIMIT));
                        if (limit <= 0)
                            limit = Long.MAX_VALUE;
                    } catch (NumberFormatException e) {
                        limit = Long.MAX_VALUE;
                    }
                }

                // Perform the search
                long count = 0;
                long idOffset = 0L;
                long idGap = 10000;
                boolean hasNoMoreBug = false;
                while (count < limit && !hasNoMoreBug) {
                    DefaultSearchData searchData = newSearchData(keys, values);
                    searchData.add("v1", new Long(idOffset).toString());
                    searchData.add("v2", new Long(idOffset + idGap).toString());

                    hasNoMoreBug = true;
                    Iterator<Issue> i = session.searchBugs(searchData, null);
                    while (i.hasNext()) {
                        Issue issue = i.next();
                        System.out.println("Bug found: " + issue.getId()
                                + " - " + issue.getShortDescription());
                        writeBugData(dataWriter, issue);
                        writeBugComment(commentWriter, issue);

                        hasNoMoreBug = false;
                        count++;
                        if (count >= limit)
                            break;
                    }
                    idOffset += idGap;
                }

                dataWriter.flush();
                dataWriter.close();
                commentWriter.flush();
                commentWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // Close the session
            session.close();
        }
    }

    private DefaultSearchData newSearchData(String[] keys, String[] values) {
        DefaultSearchData searchData = new DefaultSearchData();
        searchData.add("f1", "bug_id");
        searchData.add("f2", "bug_id");
        searchData.add("o1", "greaterthan");
        searchData.add("o2", "lessthaneq");
        searchData.add("query_format", "advanced");
        searchData.add("order", "bug_id");
        searchData.add("limit", "0");
        for (int i = 0; i < keys.length && i < values.length; i++) {
            searchData.add(keys[i], values[i]);
        }
        return searchData;
    }

    /**
     * Write bug-data file. Bug-data file provides the basic bug information.
     * The format of the file is: bugID, Type, Status, Owner, Reporter,
     * ReportDate, ModifiedDate, LastDate, Summary, Comments
     * 
     * @param writer
     * @param issue
     * @throws IOException
     */
    private void writeBugData(Writer writer, Issue issue) throws IOException {
        writer.append(issue.getId() + "\t");
        writer.append(issue.getSeverity() + "\t");
        writer.append(issue.getStatus() + "\t");
        writer.append(issue.getAssigneeName() + "\t");
        writer.append(issue.getReporterName() + "\t");
        writer.append(issue.getCreationTimestamp().getTime() + "\t");
        writer.append(issue.getDeltaTimestamp().getTime() + "\t");
        writer.append("\t"); // ignored
        writer.append(issue.getShortDescription() + "\t");
        Iterator<LongDescription> it = issue.getLongDescriptionIterator();
        while (it.hasNext()) {
            writer.append(it.next().getTheText().replaceAll("\\r|\\n", " "));
        }
        writer.append("\n");
    }

    /**
     * Write bug-comment file. Bug-comment file provides the comments from the
     * developers and the users. The format of the file is: bugID, developer,
     * date, comments
     * 
     * @param writer
     * @param issue
     * @throws IOException
     */
    private void writeBugComment(Writer writer, Issue issue) throws IOException {
        Iterator<LongDescription> it = issue.getLongDescriptionIterator();
        while (it.hasNext()) {
            LongDescription des = it.next();
            writer.append(issue.getId() + "\t");
            writer.append(des.getWho() + "\t");
            writer.append(des.getWhen().getTime() + "\t");
            writer.append(des.getTheText().replaceAll("\\r|\\n", " ") + "\n");
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

        LinkPreparer preparer = new LinkPreparer();
        preparer.load(args);
        preparer.prepare();

    }

}
